<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <base data-ice="baseUrl" href="../../../">
  <title data-ice="title">lib/backend/base.js | API Document</title>
  <link type="text/css" rel="stylesheet" href="css/style.css">
  <link type="text/css" rel="stylesheet" href="css/prettify-tomorrow.css">
  <script src="script/prettify/prettify.js"></script>
  
  
  <script src="script/manual.js"></script>
</head>
<body class="layout-container" data-ice="rootContainer">

<header>
  <a href="./">Home</a>
  
  <a href="identifiers.html">Reference</a>
  <a href="source.html">Source</a>
  
  <a data-ice="repoURL" href="https://git.oschina.net/kinuxroot/unique-model.js.git">Repository</a>
  <div class="search-box">
  <span>
    <img src="./image/search.png">
    <span class="search-input-edge"></span><input class="search-input"><span class="search-input-edge"></span>
  </span>
    <ul class="search-result"></ul>
  </div>
</header>

<nav class="navigation" data-ice="nav"><div>
  <ul>
    
  <li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/session.js~Session.html">Session</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-createSession">createSession</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-enablePersist">enablePersist</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-isPersistEnabled">isPersistEnabled</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-BaseModel">BaseModel</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-Types">Types</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-model">model</a></span></span></li>
<li data-ice="doc"><div data-ice="dirPath" class="nav-dir-path">backend</div><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/backend/base.js~Dao.html">Dao</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/backend/base.js~Session.html">Session</a></span></span></li>
<li data-ice="doc"><div data-ice="dirPath" class="nav-dir-path">model</div><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/model/base.js~Model.html">Model</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-createModel">createModel</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-getModel">getModel</a></span></span></li>
<li data-ice="doc"><div data-ice="dirPath" class="nav-dir-path">type</div><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/type/index.js~BaseType.html">BaseType</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/type/index.js~Double.html">Double</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/type/index.js~Integer.html">Integer</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/type/index.js~Text.html">Text</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/lib/type/index.js~UObject.html">UObject</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-defineType">defineType</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-toUniqueModel">toUniqueModel</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-allTypes">allTypes</a></span></span></li>
</ul>
</div>
</nav>

<div class="content" data-ice="content"><h1 data-ice="title">lib/backend/base.js</h1>
<pre class="source-code line-number raw-source-code"><code class="prettyprint linenums" data-ice="content">&apos;use strict&apos;

/** @private */
let Fiber = require(&apos;fibers&apos;);
/** @private */
let um = require(&apos;..&apos;);
/** @private */
let BaseModel = um.BaseModel;
/** @private */
let ModelStatus = BaseModel.Status;

/**
 * The base class of backend data access object.
 *
 * @public
 */
class Dao {
    /**
     * The constructor of Dao class
     *
     * @public
     * @param {backend/base/Session} [session] - The backend session object.
     */
    constructor(session) {
        this.session = session;
    }

    /**
     * Convert the UniqueModel object to BackendModel object.
     *
     * @public
     *
     * @param {model/base/Model} [uniqueModelObject] - The UniqueModel object to convert.
     *
     * @return {Object} The backend model object corresponding to the UniqueModel object.
     */
    toBackendModel(uniqueModelObject) {
        let fields = Object.create(null);
        let schema = this.uniqueModel._meta.schema;

        if ( !uniqueModelObject._dao || uniqueModelObject._complete ) {
            for ( let fieldName in schema ) {
                let fieldType = schema[fieldName];
                if ( uniqueModelObject[fieldName] != null &amp;&amp; 
                  uniqueModelObject[fieldName] != undefined ) {
                    fields[fieldName] = uniqueModelObject[fieldName];

                    if ( fieldType.name === &apos;UObject&apos; ) {
                        fields[fieldName] = fields[fieldName].id;
                    }
                }
            }
        }

        if ( &apos;id&apos; in uniqueModelObject &amp;&amp; uniqueModelObject.id ) {
            fields._id = uniqueModelObject.id;
        }

        return fields;
    }

    /**
     * Convert the backend model object object to UniqueModel object.
     *
     * @public
     *
     * @param {Object} [backendModelObject] - The backend model object object to convert.
     * @param {model/base/Model} [uniqueModelObject] - The UniqueModel object to store the converted fields.
     *
     * @return {model/base/Model} The UniqueModel object corresponding to the backend model object.
     */
    toUniqueModel(backendModelObject, uniqueModelObject) {
        let uniqueModel = this.uniqueModel;
        let schema = uniqueModel._meta.schema;

        if ( !uniqueModelObject ) {
            uniqueModelObject = new uniqueModel();
        }

        for ( let fieldName in schema ) {
            let fieldType = schema[fieldName];

            let fieldValue = backendModelObject[fieldName];
            if ( fieldType.name === &apos;UObject&apos; ) {
                let subModel = um.model.getModel(fieldType.type);
                uniqueModelObject[fieldName] = new subModel();
                uniqueModelObject[fieldName].id = String(fieldValue);
                uniqueModelObject[fieldName]._dao = this.session.getDao(subModel);
            }
            else {
                uniqueModelObject[fieldName] = fieldType.fromValue(fieldValue);
            }
        }
        uniqueModelObject.id = backendModelObject._id;

        return uniqueModelObject;
    }

    /**
     * Convert the Array of backend model objects to Array of UniqueModel objects.
     *
     * @public
     *
     * @param {Array} [backendModelObjectArray] - The Array of backend model objects object to convert.
     *
     * @return {Array} The Array of UniqueModels  object corresponding to the Array of backend model objects.
     */
    toUniqueModelArray(backendModelObjectArray) {
        let self = this;

        return backendModelObjectArray.map(backendModelObject =&gt; {
                return self.toUniqueModel(backendModelObject);
            }
        );
    }

    /**
     * Execute the asynchronous operation of backend model object.
     * It use Fibers to convert asynchronous to synchronous operation.
     * If the asynchronous pass a error, then this function will throw exception.
     *
     * @public
     *
     * @param {String} [operation] - The operation to execute.
     *
     * @return {*} The operation result.
     */
    execute(operation) {
        let fiber = Fiber.current;
        let error = null;
        let result = null;
        let args = Array.from(arguments);

        let operationAsync = operation + &apos;Async&apos;;
        let callback = function(err, res) {
            error = err;
            result = res;
    
            fiber.run();
        }
        args = args.slice(1);
        args.push(callback);

        this[operationAsync].apply(this, args);
        Fiber.yield();
    
        if ( error ) {
            throw error;
        }
    
        return result;
    }

    /**
     * Create the UniqueModel object and persist it through backend.
     * It will call the asyncCreate method by using execute method.
     *
     * @public
     *
     * @param {model/base/Model} [uniqueModelObject] - The UniqueModel object to create.
     *
     * @return {model/base/Model} The created UniqueModel object.
     */
    create(uniqueModelObject) {
        let backendModelObject = this.toBackendModel(uniqueModelObject);
        let createdBackendModelObject = this.execute(&apos;create&apos;, backendModelObject);
        this.toUniqueModel(createdBackendModelObject, uniqueModelObject);

        if ( uniqueModelObject ) {
            uniqueModelObject._dao = this;
            uniqueModelObject._status = ModelStatus.Managed;
            uniqueModelObject._complete = true;
        }

        return uniqueModelObject;
    }

    /**
     * Refresh the persisted UniqueModel object.
     * It will load the UniqueModel object from backend session according to the id of object.
     * It will call the findOne method to get the data.
     *
     * @public
     *
     * @param {model/base/Model} [uniqueModelObject] - The UniqueModel object to refresh.
     *
     * @return {model/base/Model} The refreshed UniqueModel object.
     */
    refresh(uniqueModelObject) {
        let backendModelObject = this.toBackendModel(uniqueModelObject);
        let condition = {
            [this.getObjectIdKey()]: this.getObjectId(backendModelObject)
        };
        let foundBackendModelObject = this.execute(&apos;findOne&apos;, condition);

        if ( !foundBackendModelObject ) {
            return null;
        }

        this.toUniqueModel(foundBackendModelObject, uniqueModelObject);
        uniqueModelObject._dao = this;
        uniqueModelObject._status = ModelStatus.Managed;
        uniqueModelObject._complete = true;

        return uniqueModelObject;
    }

    /**
     * Find the objects by condition.
     * If the field of object is another object, it will only get the id of object,
     * and the other fields will be loaded when you first access the object.
     *
     * @public
     *
     * @param {Object} [condition] - The query condition
     *
     * @return {Array} The Array of UniqueModel objects that match conditions.
     */
    find(condition) {
        let foundBackendModelObjects = this.execute(&apos;find&apos;, condition);
        let foundUniqueModelObjects = this.toUniqueModelArray(foundBackendModelObjects);
        foundUniqueModelObjects.forEach((uniqueModelObject) =&gt; {
            uniqueModelObject._dao = this;
            uniqueModelObject._status = ModelStatus.Managed;
        });

        return foundUniqueModelObjects;
    }

    /**
     * Find one object by condition.
     * If the field of object is another object, it will only get the id of object,
     * and the other fields will be loaded when you first access the object.
     *
     * @public
     *
     * @param {Object} [condition] - The query condition
     *
     * @return {model/base/Model} The UniqueModel object that match conditions.
     */
    findOne(condition) {
        let foundBackendModelObject = this.execute(&apos;findOne&apos;, condition);
        if ( !foundBackendModelObject ) {
            return null;
        }

        let foundUniqueModelObject = this.toUniqueModel(foundBackendModelObject);
        foundUniqueModelObject._dao = this;
        foundUniqueModelObject._status = ModelStatus.Managed;
        foundUniqueModelObject._complete = true;

        return foundUniqueModelObject;
    }

    /**
     * Update the objects match some conditions.
     * The update operation will be performed according to the argument doc.
     *
     * @public
     *
     * @param {Object} [condition] - The query condition
     * @param {Object} [doc] - The update actions
     * @param {Object} [options] - The update options
     * @param {Boolean} [options.multi] - Update multiple objects if it is true, or only one object will be updated.
     *
     * @return {Array} The Array of updated UniqueModel objects that match conditions.
     */
    update(condition, doc, options) {
        return this.execute(&apos;update&apos;, condition, doc, options);
    }

    /**
     * Update only one object match some conditions.
     * The update operation will be performed according to the argument doc.
     *
     * @public
     *
     * @param {Object} [condition] - The query condition
     * @param {Object} [doc] - The update actions
     * @param {Object} [options] - The update options
     * @param {Boolean} [options.new] - updateOne will return updated object when this argument is true.
     *                                  Or it will return the object before update.
     *
     * @return {model/base/Model} The updated UniqueModel object that match conditions.
     */
    updateOne(condition, doc, options) {
        let foundBackendModelObject = this.execute(&apos;updateOne&apos;, condition, doc, options);
        let foundUniqueModelObject = this.toUniqueModel(foundBackendModelObject);
        foundUniqueModelObject._dao = this;
        foundUniqueModelObject._status = ModelStatus.Managed;
        uniqueModelObject._complete = true;

        return foundUniqueModelObject;
    }

    /**
     * Remove some objects.
     * If the argument is an UniqueModel object, the method will remove this object from persistent session only.
     * If the argument is an condition object, the method will remove all objects match conditions.
     *
     * @public
     *
     * @param {Object} [condition] - The UniqueModel object or condition object.
     */
    remove(condition) {
        if ( condition instanceof um.BaseModel ) {
            let uniqueModelObject = condition;
            let backendModelObject = this.toBackendModel(uniqueModelObject);
            condition = {
                [this.getObjectIdKey()]: this.getObjectId(backendModelObject)
            };

            uniqueModelObject.status = ModelStatus.Removed;
        }

        return this.execute(&apos;remove&apos;, condition);
    }

    // interface
    createAsync(backendModel, callback) {
        callback(null, null);
    }

    // interface
    getObjectIdKey() {
        return null;
    }

    getObjectId(backendModelObject) {
        return backendModelObject[this.getObjectIdKey()];
    }

    // override
    findAsync(condition, callback) {
        callback(null, null);
    }

    // override
    findOneAsync(condition, callback) {
        callback(null, null);
    }

    // override
    updateAsync(condition, doc, callback) {
        callback(null, null);
    }

    // override
    updateOneAsync(condition, doc, callback) {
        callback(null, null);
    }

    // override
    removeAsync(condition, callback) {
        callback(null, null);
    }
}

class Session {
    constructor(options) {
        this.daos = Object.create(null);
    }

    getDao(model) {
        if ( !(model._meta.name in this.daos) ) {
            this.daos[model._meta.name] = this.createDao(model);
        }

        return this.daos[model._meta.name];
    }

    // interface
    createDao(model) {
        return null;
    }
}

module.exports = {
        Dao,
        Session
};
</code></pre>

</div>

<footer class="footer">
  Generated by <a href="https://esdoc.org">ESDoc<span data-ice="esdocVersion">(0.4.3)</span></a>
</footer>

<script src="script/search_index.js"></script>
<script src="script/search.js"></script>
<script src="script/pretty-print.js"></script>
<script src="script/inherited-summary.js"></script>
<script src="script/test-summary.js"></script>
<script src="script/inner-link.js"></script>
<script src="script/patch-for-local.js"></script>
</body>
</html>
